/**
 * @file TrackerAddOn.cpp
 * @brief Tracker插件实现文件
 * @details 实现了Tracker右键菜单插件的功能
 */

#include "TrackerAddOn.h"
#include <Alert.h>
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <Path.h>
#include <String.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <Roster.h>
#include <NodeInfo.h>
#include <Bitmap.h>
#include <Font.h>
#include <MenuItem.h>
#include <PopUpMenu.h>

/**
 * @brief 构造函数
 */
HZipTrackerAddOn::HZipTrackerAddOn()
{
    // 初始化时不做任何操作
}

/**
 * @brief 析构函数
 */
HZipTrackerAddOn::~HZipTrackerAddOn()
{
    // 析构时不做任何操作
}

/**
 * @brief 处理Tracker的Process方法
 * @param cwd 当前工作目录
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 */
void HZipTrackerAddOn::Process(const char *cwd, const entry_ref *refs, int32 count)
{
    // 这个方法不会被直接调用，实际处理在process_refs函数中
}

/**
 * @brief 生成右键菜单项
 * @param cwd 当前工作目录
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 * @param items 菜单项数组
 * @param messages 消息数组
 * @return 添加的菜单项数量
 */
int32 HZipTrackerAddOn::GetMenuItems(const char *cwd, const entry_ref *refs, int32 count, BMenuItem **items, BMessage **messages)
{
    if (count <= 0 || refs == NULL)
        return 0;

    // 检查第一个选中的文件是否为压缩文件
    BEntry entry(&refs[0]);
    BPath path;
    entry.GetPath(&path);

    int32 addedItems = 0;

    if (_IsArchiveFile(path.Path()))
    {
        // 如果是压缩文件，添加解压缩菜单项
        BMessage *extractMsg = new BMessage(MSG_ADDON_EXTRACT);
        items[addedItems] = _CreateIconMenuItem("解压缩", extractMsg, 0xF1C6); // 使用解压缩图标
        messages[addedItems] = extractMsg;
        addedItems++;
    }
    else
    {
        // 如果不是压缩文件，添加压缩菜单项
        BMessage *zipMsg = new BMessage(MSG_ADDON_COMPRESS_ZIP);
        items[addedItems] = _CreateIconMenuItem("压缩为ZIP", zipMsg, 0xF1C6); // 使用压缩图标
        messages[addedItems] = zipMsg;
        addedItems++;

        BMessage *tarMsg = new BMessage(MSG_ADDON_COMPRESS_TAR);
        items[addedItems] = _CreateIconMenuItem("压缩为TAR", tarMsg, 0xF1C6);
        messages[addedItems] = tarMsg;
        addedItems++;

        BMessage *tarGzMsg = new BMessage(MSG_ADDON_COMPRESS_TARGZ);
        items[addedItems] = _CreateIconMenuItem("压缩为TAR.GZ", tarGzMsg, 0xF1C6);
        messages[addedItems] = tarGzMsg;
        addedItems++;

        BMessage *tarBz2Msg = new BMessage(MSG_ADDON_COMPRESS_TARBZ2);
        items[addedItems] = _CreateIconMenuItem("压缩为TAR.BZ2", tarBz2Msg, 0xF1C6);
        messages[addedItems] = tarBz2Msg;
        addedItems++;

        BMessage *tarZstMsg = new BMessage(MSG_ADDON_COMPRESS_TARZST);
        items[addedItems] = _CreateIconMenuItem("压缩为TAR.ZST", tarZstMsg, 0xF1C6);
        messages[addedItems] = tarZstMsg;
        addedItems++;
    }

    return addedItems;
}

/**
 * @brief 检查文件是否为压缩文件
 * @param path 文件路径
 * @return 是否为压缩文件
 */
bool HZipTrackerAddOn::_IsArchiveFile(const char *path) const
{
    if (path == NULL)
        return false;

    BString pathStr(path);

    // 检查文件扩展名
    if (pathStr.IFindLast(".zip") >= 0 ||
        pathStr.IFindLast(".tar") >= 0 ||
        pathStr.IFindLast(".tgz") >= 0 ||
        pathStr.IFindLast(".tar.gz") >= 0 ||
        pathStr.IFindLast(".tbz2") >= 0 ||
        pathStr.IFindLast(".tar.bz2") >= 0 ||
        pathStr.IFindLast(".tzst") >= 0 ||
        pathStr.IFindLast(".tar.zst") >= 0 ||
        pathStr.IFindLast(".gz") >= 0 ||
        pathStr.IFindLast(".bz2") >= 0 ||
        pathStr.IFindLast(".zst") >= 0)
    {
        // 检查是否为文件而非目录
        BEntry entry(path);
        return entry.IsFile();
    }

    return false;
}

/**
 * @brief 获取图标字体
 * @return 图标字体
 */
BFont HZipTrackerAddOn::_GetIconFont() const
{
    BFont font;
    font.SetFamilyAndStyle("FontAwesome", "Solid");
    font.SetSize(12.0);
    return font;
}

/**
 * @brief 创建带图标的菜单项
 * @param label 菜单项标签
 * @param message 菜单项消息
 * @param iconChar 图标字符
 * @return 创建的菜单项
 */
BMenuItem *HZipTrackerAddOn::_CreateIconMenuItem(const char *label, BMessage *message, uint32 iconChar) const
{
    // 创建带图标的菜单项
    BString iconString;
    iconString.Append((char *)&iconChar, 4);

    BMenuItem *item = new BMenuItem(label, message);

    // 设置菜单项图标
    // 注意：实际实现可能需要根据Haiku OS的API调整
    // 这里简化处理，实际应用中可能需要更复杂的图标设置

    return item;
}

/**
 * @brief 执行压缩操作
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 * @param format 压缩格式
 */
void HZipTrackerAddOn::_DoCompress(const entry_ref *refs, int32 count, const char *format)
{
    if (count <= 0 || refs == NULL || format == NULL)
        return;

    // 获取第一个文件的路径作为基准
    BEntry firstEntry(&refs[0]);
    BPath firstPath;
    firstEntry.GetPath(&firstPath);

    // 构建目标压缩文件路径
    BPath parentPath;
    BEntry parentEntry;
    firstEntry.GetParent(&parentEntry);
    parentEntry.GetPath(&parentPath);

    // 如果只有一个文件，使用文件名作为压缩包名称
    BString targetName;
    if (count == 1)
    {
        targetName = firstPath.Leaf();
    }
    else
    {
        // 如果有多个文件，使用父目录名称
        targetName = parentPath.Leaf();
    }

    // 添加扩展名
    if (strcmp(format, "zip") == 0)
    {
        targetName.Append(".zip");
    }
    else if (strcmp(format, "tar") == 0)
    {
        targetName.Append(".tar");
    }
    else if (strcmp(format, "tar.gz") == 0)
    {
        targetName.Append(".tar.gz");
    }
    else if (strcmp(format, "tar.bz2") == 0)
    {
        targetName.Append(".tar.bz2");
    }
    else if (strcmp(format, "tar.zst") == 0)
    {
        targetName.Append(".tar.zst");
    }

    BPath targetPath(parentPath.Path());
    targetPath.Append(targetName.String());

    // 构建源文件路径数组
    BString sourcePaths;
    for (int32 i = 0; i < count; i++)
    {
        BEntry entry(&refs[i]);
        BPath path;
        entry.GetPath(&path);

        if (i > 0)
        {
            sourcePaths.Append(" ");
        }
        sourcePaths.Append(path.Path());
    }

    // 执行压缩操作
    bool result = fEngine.Compress(format, sourcePaths.String(), targetPath.Path());

    // 显示结果提示
    if (result)
    {
        BAlert *alert = new BAlert("压缩成功", "文件已成功压缩", "确定");
        alert->Go();
    }
    else
    {
        BAlert *alert = new BAlert("压缩失败", "文件压缩失败", "确定");
        alert->Go();
    }
}

/**
 * @brief 执行解压缩操作
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 */
void HZipTrackerAddOn::_DoExtract(const entry_ref *refs, int32 count)
{
    if (count <= 0 || refs == NULL)
        return;

    // 目前只处理第一个选中的压缩文件
    BEntry entry(&refs[0]);
    BPath path;
    entry.GetPath(&path);

    // 获取父目录作为解压目标
    BPath parentPath;
    BEntry parentEntry;
    entry.GetParent(&parentEntry);
    parentEntry.GetPath(&parentPath);

    // 执行解压缩操作
    bool result = fEngine.Extract(path.Path(), parentPath.Path());

    // 显示结果提示
    if (result)
    {
        BAlert *alert = new BAlert("解压缩成功", "文件已成功解压缩", "确定");
        alert->Go();
    }
    else
    {
        BAlert *alert = new BAlert("解压缩失败", "文件解压缩失败", "确定");
        alert->Go();
    }
}

// 导出的C函数实现

/**
 * @brief 获取插件API版本
 * @return API版本号
 */
extern "C" int32 api_version(void)
{
    // 返回Tracker插件API版本
    return 1;
}

/**
 * @brief 生成右键菜单项
 * @param cwd 当前工作目录
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 * @param items 菜单项数组
 * @param messages 消息数组
 * @return 添加的菜单项数量
 */
extern "C" int32 add_on_init(const char *cwd, const entry_ref *refs, int32 count, BMenuItem **items, BMessage **messages)
{
    // 创建插件实例并调用GetMenuItems方法
    HZipTrackerAddOn addon;
    return addon.GetMenuItems(cwd, refs, count, items, messages);
}

/**
 * @brief 处理菜单项点击
 * @param cwd 当前工作目录
 * @param refs 选中的文件引用数组
 * @param count 选中的文件数量
 * @param message 菜单项消息
 */
extern "C" void process_refs(const char *cwd, const entry_ref *refs, int32 count, BMessage *message)
{
    if (message == NULL || count <= 0 || refs == NULL)
        return;

    // 创建插件实例
    HZipTrackerAddOn addon;

    // 根据消息类型执行相应操作
    switch (message->what)
    {
    case MSG_ADDON_COMPRESS_ZIP:
        addon._DoCompress(refs, count, "zip");
        break;

    case MSG_ADDON_COMPRESS_TAR:
        addon._DoCompress(refs, count, "tar");
        break;

    case MSG_ADDON_COMPRESS_TARGZ:
        addon._DoCompress(refs, count, "tar.gz");
        break;

    case MSG_ADDON_COMPRESS_TARBZ2:
        addon._DoCompress(refs, count, "tar.bz2");
        break;

    case MSG_ADDON_COMPRESS_TARZST:
        addon._DoCompress(refs, count, "tar.zst");
        break;

    case MSG_ADDON_EXTRACT:
        addon._DoExtract(refs, count);
        break;

    default:
        break;
    }
}